<template>
  <div class="demo-inner-divider">基础用法</div>
  <e-treeV2 :data="data" :props="defaultProps" node-key="label" :default-expanded-keys="['Level one 2']" @node-click="handleNodeClick" isShowLine/>

  <div class="demo-inner-divider">可选择</div>
  <e-treeV2
    :props="props"
    :load="loadNode"
    lazy
    show-checkbox
    @check-change="handleCheckChange"
  />

  <div class="demo-inner-divider">懒加载自定义叶子节点</div>
  <e-treeV2 :props="propsCustom" :load="loadNodeCustom" lazy show-checkbox />

  <div class="demo-inner-divider">禁用复选框</div>
  <p>节点的复选框可以设置为禁用。</p> 
  <p>在示例中，通过 disabled 设置禁用状态。 相应的复选框已禁用，不能点击。default-checked-keys 设置默认选中的节点。 需要注意的是，此时必须设置 node-key， 其值为节点数据中的一个字段名，该字段在整棵树中是唯一的。</p> 
  <e-treeV2 :data="dataDis" :props="propsDis" node-key="id" :default-checked-keys="[4,7]" isShowLine show-checkbox  default-expand-all/>

  <div class="demo-inner-divider">默认展开以及默认选中</div>
  <div>
    <p>树节点可以在初始化阶段被设置为展开和选中。</p> 
    <p>分别通过 default-expanded-keys 和 default-checked-keys 设置默认展开和默认选中的节点。 需要注意的是，此时必须设置 node-key， 其值为节点数据中的一个字段名，该字段在整棵树中是唯一的。</p> 
  </div>
  <e-treeV2
    :data="dataCheck"
    show-checkbox
    node-key="id"
    :default-expanded-keys="[2, 3]"
    :default-checked-keys="[5]"
    :props="propsCheck"
  />

  <div class="demo-inner-divider">树节点的选择</div>
  <p>本例展示如何获取和设置选中节点。 获取和设置各有两种方式：通过 node 或通过 key。 如果需要通过 key 来获取或设置，则必须设置 node-key。</p>
  <e-treeV2
    ref="treeRef"
    :data="dataTree"
    show-checkbox
    default-expand-all
    node-key="id"
    highlight-current
    :props="propsTree"
  />

  <div class="buttons">
    <e-button @click="getCheckedNodes">get by node</e-button>
    <e-button @click="getCheckedKeys">get by key</e-button>
    <e-button @click="setCheckedNodes">set by node</e-button>
    <e-button @click="setCheckedKeys">set by key</e-button>
    <e-button @click="resetChecked">reset</e-button>
  </div>

  <div class="demo-inner-divider">自定义节点内容</div>
  <div>可以通过两种方法进行树节点内容的自定义：render-content 和 scoped slot。 使用 render-content 指定渲染函数，该函数返回需要的节点区内容即可。 渲染函数的用法请参考 Vue 文档。 使用 scoped slot 会传入两个参数 node 和 data，分别表示当前节点的 Node 对象和当前节点的数据。 注意：由于 JSFiddle 不支持 JSX 语法，所以 render-content 示例无法在那里运行。 但是在实际的项目中，只要正确地配置了相关依赖，就可以正常运行。</div>
  <div class="custom-tree-container">
    <p>Using render-content</p>
    <e-treeV2
      :data="dataSource"
      show-checkbox
      node-key="id"
      default-expand-all
      :expand-on-click-node="false"
      :render-content="renderContent"
    />
    <p>Using scoped slot</p>
    <e-treeV2
      :data="dataSource"
      show-checkbox
      node-key="id"
      default-expand-all
      :expand-on-click-node="false"
    >
      <template #default="{ node, data }">
        <span class="custom-tree-node">
          <span>{{ node.label }}</span>
          <span>
            <a @click="append(data)"> Append </a>
            <a style="margin-left: 8px" @click="remove(node, data)"> Delete </a>
          </span>
        </span>
      </template>
    </e-treeV2>
  </div>

  <div class="demo-inner-divider">自定义节点类名</div>
  <div>节点的类名支持自定义。使用 props.class 来建立节点的类名。</div>
  <div class="custom-tree-node-container">
    <e-treeV2
      :data="dataCustom"
      show-checkbox
      node-key="id"
      default-expand-all
      :expand-on-click-node="false"
      :props="{ class: customNodeClass }"
    />
  </div>

  <div class="demo-inner-divider">树节点过滤</div>
  <div>
    调用 Tree 实例对象的 filter 方法来过滤树节点。 方法的参数就是过滤关键字。 需要注意的是，此时需要设置 filter-node-method 属性，其值为过滤函数。
  </div>
  <e-input v-model="filterText" placeholder="Filter keyword" />

  <e-treeV2
    ref="treeFilterRef"
    class="filter-tree"
    :data="dataFilter"
    :props="propsFilter"
    default-expand-all
    :filter-node-method="filterNode"
  />

  <div class="demo-inner-divider">节点过滤、高亮</div>
  <div>
    通过组件renderContent+filter方法实现高亮
  </div>
  <e-input v-model="filterLightText" placeholder="Filter keyword" />
  <e-treeV2
    ref="treeFilterLightRef"
    class="filter-tree"
    :data="dataLightFilter"
    :props="propsLightFilter"
    default-expand-all
    :filter-node-method="filterLightNode"
    :render-content="renderLightContent"
  />
  <div class="demo-inner-divider">手风琴模式</div>
  <p>对于同一级的节点，每次只能展开一个</p>
  <e-treeV2
    :data="dataAcc"
    :props="propsAcc"
    accordion
    show-checkbox
    @node-click="handleNodeClick"
  />

  <div class="demo-inner-divider">通过 draggable 属性可让节点变为可拖拽</div>
  <e-treeV2
    :allow-drop="allowDrop"
    :allow-drag="allowDrag"
    :data="dataDrag"
    draggable
    default-expand-all
    node-key="id"
    @node-drag-start="handleDragStart"
    @node-drag-enter="handleDragEnter"
    @node-drag-leave="handleDragLeave"
    @node-drag-over="handleDragOver"
    @node-drag-end="handleDragEnd"
    @node-drop="handleDrop"
  />

  <operationalTree />

  <treeMdV2 class="markdown-body" />
</template>

<script setup>
import {ref,watch} from "vue"

import operationalTree from "./treev2/operationalTree.vue"
import treeMdV2 from "../../docs/tree-v2.md"

const handleNodeClick = (data) => {
  console.log(data)
}

const data = [
  {
    label: 'Level one 1',
    children: [
      {
        label: 'Level two 1-1',
        children: [
          {
            label: 'Level three 1-1-1',
          },
        ],
      },
    ],
  },
  {
    label: 'Level one 2',
    children: [
      {
        label: 'Level two 2-1',
        children: [
          {
            label: 'Level three 2-1-1',
          },
        ],
      },
      {
        label: 'Level two 2-2',
        children: [
          {
            label: 'Level three 2-2-1',
          },
        ],
      },
    ],
  },
  {
    label: 'Level one 3',
    children: [
      {
        label: 'Level two 3-1',
        children: [
          {
            label: 'Level three 3-1-1',
          },
        ],
      },
      {
        label: 'Level two 3-2',
        children: [
          {
            label: 'Level three 3-2-1',
          },
        ],
      },
    ],
  },
]

const defaultProps = {
  children: 'children',
  label: 'label',
}


// let count = 1
const props = {
  label: 'name',
  children: 'zones',
}


const handleCheckChange = (data,checked,indeterminate) => {
  console.log(data, checked, indeterminate)
}

const loadNode = (node, resolve) => {
  if (node.level === 0) {
    return resolve([{ name: 'Root1' }, { name: 'Root2' }])
  }
  if (node.level > 3) return resolve([])

  let hasChild = false
  if (node.data.name === 'region1') {
    hasChild = true
  } else if (node.data.name === 'region2') {
    hasChild = false
  } else {
    hasChild = Math.random() > 0.5
  }

  setTimeout(() => {
    let data= []
    if (hasChild) {
      data = [
        {
          name: `zone${count++}`,
        },
        {
          name: `zone${count++}`,
        },
      ]
    } else {
      data = []
    }

    resolve(data)
  }, 500)
}


const propsCustom = {
  label: 'name',
  children: 'zones',
  isLeaf: 'leaf',
}

const loadNodeCustom = (node, resolve) => {
  if (node.level === 0) {
    return resolve([{ name: 'region' }])
  }
  if (node.level > 1) return resolve([])

  setTimeout(() => {
    const data = [
      {
        name: 'leaf',
        leaf: true,
      },
      {
        name: 'zone',
      },
    ]

    resolve(data)
  }, 500)
}

const propsDis={
  children: 'children',
  label: 'label',
  disabled: 'disabled',
}

const dataDis=[
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 3,
        label: 'Level two 2-1',
        children: [
          {
            id: 4,
            label: 'Level three 3-1-1',
          },
          {
            id: 5,
            label: 'Level three 3-1-2',
            disabled: true,
          },
        ],
      },
      {
        id: 2,
        label: 'Level two 2-2',
        disabled: true,
        children: [
          {
            id: 6,
            label: 'Level three 3-2-1',
          },
          {
            id: 7,
            label: 'Level three 3-2-2',
            disabled: true,
          },
        ],
      },
    ],
  },
]

const dataCheck=[
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        label: 'Level two 1-1',
        children: [
          {
            id: 9,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: 'Level one 2',
    children: [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    label: 'Level one 3',
    children: [
      {
        id: 7,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        label: 'Level two 3-2',
      },
    ],
  },
]

const propsCheck={
  children: 'children',
  label: 'label',
}

const treeRef = ref()
const propsTree={
  children: 'children',
  label: 'label',
}
const dataTree=[
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        label: 'Level two 1-1',
        children: [
          {
            id: 9,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: 'Level one 2',
    children: [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    label: 'Level one 3',
    children: [
      {
        id: 7,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        label: 'Level two 3-2',
      },
    ],
  },
]

const getCheckedNodes = () => {
  console.log(treeRef.value.getCheckedNodes(false, false))
}
const getCheckedKeys = () => {
  console.log(treeRef.value.getCheckedKeys(false))
}
const setCheckedNodes = () => {
  treeRef.value.setCheckedNodes(
    [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 9,
        label: 'Level three 1-1-1',
      },
    ],
    false
  )
}
const setCheckedKeys = () => {
  treeRef.value.setCheckedKeys([3], false)
}
const resetChecked = () => {
  treeRef.value.setCheckedKeys([], false)
}


let id = 1000

const append = (data) => {
  const newChild = { id: id++, label: 'testtest', children: [] }
  if (!data.children) {
    data.children = []
  }
  data.children.push(newChild)
  dataSource.value = [...dataSource.value]
}

const remove = (node, data) => {
  const parent = node.parent
  const children = parent.data.children || parent.data
  const index = children.findIndex((d) => d.id === data.id)
  children.splice(index, 1)
  dataSource.value = [...dataSource.value]
}

const renderContent = (
  h,
  {
    node,
    data,
    store,
  }
) => {
  return h(
    'span',
    {
      class: 'custom-tree-node',
    },
    h('span', null, node.label),
    h(
      'span',
      null,
      h(
        'a',
        {
          onClick: () => append(data),
        },
        'Append '
      ),
      h(
        'a',
        {
          style: 'margin-left: 8px',
          onClick: () => remove(node, data),
        },
        'Delete'
      )
    )
  )
}

const dataSource = ref([
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        label: 'Level two 1-1',
        children: [
          {
            id: 9,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: 'Level one 2',
    children: [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    label: 'Level one 3',
    children: [
      {
        id: 7,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        label: 'Level two 3-2',
      },
    ],
  },
])

const customNodeClass = (data, node) => {
  if (data.isPenultimate) {
    return 'is-penultimate'
  }
  return null
}

const dataCustom=[
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        label: 'Level two 1-1',
        isPenultimate: true,
        children: [
          {
            id: 9,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: 'Level one 2',
    isPenultimate: true,
    children: [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    label: 'Level one 3',
    isPenultimate: true,
    children: [
      {
        id: 7,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        label: 'Level two 3-2',
      },
    ],
  },
]

const filterText = ref('')
const treeFilterRef = ref()

const propsFilter = {
  children: 'children',
  label: 'label',
}

watch(filterText, (val) => {
  treeFilterRef.value.filter(val)
})

const filterNode = (value, data) => {
  if (!value) return true
  console.log(data)
  return data.label.includes(value)
}

const dataFilter=[
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        label: 'Level two 1-1',
        children: [
          {
            id: 9,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: 'Level one 2',
    children: [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    label: 'Level one 3',
    children: [
      {
        id: 7,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        label: 'Level two 3-2',
      },
    ],
  },
]

const filterLightText = ref('')
const treeFilterLightRef = ref()

const propsLightFilter = {
  children: 'children',
  label: 'label',
}

watch(filterLightText, (val) => {
  treeFilterLightRef.value.filter(val)
})


const getMatchIndex=(title)=> {
  if (!filterLightText.value) return -1;
  // console.log('filterLightText.value.toLowerCase()',filterLightText.value.toLowerCase())
  return title.toLowerCase().indexOf(filterLightText.value.toLowerCase());
}

const filterLightNode = (value, data) => {
  if (!value) return true
  // console.log(data)
  return data.label.includes(value)
}

const dataLightFilter=[
  {
    id: 1,
    label: 'Level one 1',
    children: [
      {
        id: 4,
        label: 'Level two 1-1',
        children: [
          {
            id: 9,
            label: 'Level three 1-1-1',
          },
          {
            id: 10,
            label: 'Level three 1-1-2',
          },
        ],
      },
    ],
  },
  {
    id: 2,
    label: 'Level one 2',
    children: [
      {
        id: 5,
        label: 'Level two 2-1',
      },
      {
        id: 6,
        label: 'Level two 2-2',
      },
    ],
  },
  {
    id: 3,
    label: 'Level one 3',
    children: [
      {
        id: 7,
        label: 'Level two 3-1',
      },
      {
        id: 8,
        label: 'Level two 3-2',
      },
    ],
  },
]

const renderLightContent = (
  h,
  {
    node,
    data,
    store,
  }
) => {

  const index=getMatchIndex(node.label)
  let filterBefore=node.label.substr(0,index)
  let filterText=node.label.substr(index,filterLightText.value.length)
  let filterLast=node.label.substr(index+filterLightText.value.length)
  const hasLight=h('span',{},h('span',null,filterBefore),h('span',{style:{'color':'#337DFF'}},filterText),h('span',filterLast))
  let contentComp=index<0?node.label:hasLight;
  return h(
    'span',
    {
      class: 'custom-tree-node',
    },
    h('span', null, contentComp),
  )
}

const propsAcc={
  children: 'children',
  label: 'label',
}

const dataAcc= [
  {
    label: 'Level one 1',
    children: [
      {
        label: 'Level two 1-1',
        children: [
          {
            label: 'Level three 1-1-1',
          },
        ],
      },
    ],
  },
  {
    label: 'Level one 2',
    children: [
      {
        label: 'Level two 2-1',
        children: [
          {
            label: 'Level three 2-1-1',
          },
        ],
      },
      {
        label: 'Level two 2-2',
        children: [
          {
            label: 'Level three 2-2-1',
          },
        ],
      },
    ],
  },
  {
    label: 'Level one 3',
    children: [
      {
        label: 'Level two 3-1',
        children: [
          {
            label: 'Level three 3-1-1',
          },
        ],
      },
      {
        label: 'Level two 3-2',
        children: [
          {
            label: 'Level three 3-2-1',
          },
        ],
      },
    ],
  },
]

const handleDragStart = (node, ev) => {
  console.log('drag start', node)
}
const handleDragEnter = (draggingNode,dropNode,ev) => {
  console.log('tree drag enter:', dropNode.label)
}
const handleDragLeave = (draggingNode,dropNode,ev) => {
  console.log('tree drag leave:', dropNode.label)
}
const handleDragOver = (draggingNode, dropNode, ev) => {
  console.log('tree drag over:', dropNode.label)
}
const handleDragEnd = (draggingNode,dropNode,dropType,ev) => {
  console.log('tree drag end:', dropNode && dropNode.label, dropType)
}
const handleDrop = (draggingNode,dropNode,dropType,ev) => {
  console.log('tree drop:', dropNode.label, dropType)
}
const allowDrop = (draggingNode, dropNode, type) => {
  if (dropNode.data.label === 'Level two 3-1') {
    return type !== 'inner'
  } else {
    return true
  }
}
const allowDrag = (draggingNode) => {
  return !draggingNode.data.label.includes('Level three 3-1-1')
}


const dataDrag= [
  {
    label: 'Level one 1',
    children: [
      {
        label: 'Level two 1-1',
        children: [
          {
            label: 'Level three 1-1-1',
          },
        ],
      },
    ],
  },
  {
    label: 'Level one 2',
    children: [
      {
        label: 'Level two 2-1',
        children: [
          {
            label: 'Level three 2-1-1',
          },
        ],
      },
      {
        label: 'Level two 2-2',
        children: [
          {
            label: 'Level three 2-2-1',
          },
        ],
      },
    ],
  },
  {
    label: 'Level one 3',
    children: [
      {
        label: 'Level two 3-1',
        children: [
          {
            label: 'Level three 3-1-1',
          },
        ],
      },
      {
        label: 'Level two 3-2',
        children: [
          {
            label: 'Level three 3-2-1',
          },
        ],
      },
    ],
  },
]
</script>

<style scoped>
:deep(.custom-tree-node) {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  height: 26px;
  padding-right: 8px;
}

:deep(.is-penultimate > .haloe-tree-node__content) {
  color: #626aef;
}

:deep(.haloe-tree-node.is-expanded.is-penultimate > .haloe-tree-node__children) {
  display: flex;
  flex-direction: row;
}
:deep(.is-penultimate > .haloe-tree-node__children > div) {
  width: 25%;
}
</style>